package org.example.spring.cycle.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.InitBinder;

import javax.annotation.PostConstruct;

/**
 * 初始化顺序
 * Spring中⼀个Bean的创建⼤概分为以下⼏个步骤：
 * 1. 推断构造⽅法
 * 2. 实例化
 * 3. 填充属性、也就是依赖注⼊
 * 4. 处理Aware回调
 * 5. 初始化前、处理@PostConstruct注解
 * 6. 初始化、处理InitializingBean接⼝
 * 7. 初始化后、进⾏AOP
 *
 * @author hzq
 * @date 2022/3/12 13:45
 */
//@Component
public class BeanInit implements
        BeanNameAware,
        BeanClassLoaderAware,
        EnvironmentAware,
        ApplicationContextAware,
        BeanPostProcessor,
        InitializingBean,
        DisposableBean {

    private ExampleInit exampleInit;
    private ApplicationContext applicationContext;
    private Environment environment;

    // 第一步 - 第二步
    public BeanInit() {
        System.out.println("第一步 - 第二步 -- BeanInit -- 构造函数");
    }

    // 第三步
    // 需要先初始化 ExampleInit 实例
    @Autowired
    public void setExampleInit(ExampleInit exampleInit) {
        System.out.println("第三步 -- BeanInit -- setExampleInit -- " + exampleInit.getBeanName());
        this.exampleInit = exampleInit;
    }

    // 第五步
    @PostConstruct
    public void init() {
        System.out.println("第五步 -- BeanInit -- init -- @PostConstruct");
    }

    public void destroy() throws Exception {
        System.out.println("BeanInit -- destroy -- DisposableBean");
    }

    // 第六步
    public void afterPropertiesSet() throws Exception {
        System.out.println("第六步 -- BeanInit -- afterPropertiesSet -- InitializingBean");
        // applicationContext.getBean(ExampleInit.class)
        // 如果容器中没有ExampleInit实例的话 先初始化ExampleInit实例 在返回实例 (有则直接返回实例)
        ExampleInit exampleInit = this.applicationContext.getBean(ExampleInit.class);
        System.out.println("第六步 -- BeanInit -- afterPropertiesSet -- InitializingBean -- " + exampleInit.getBeanName());
    }

    // 第四步
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("第四步 -- BeanInit -- setApplicationContext -- ApplicationContextAware");
        this.applicationContext = applicationContext;
    }

    // 第四步
    public void setEnvironment(Environment environment) {
        System.out.println("第四步 -- BeanInit -- setEnvironment -- EnvironmentAware");
        this.environment = environment;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("第四步 -- BeanInit -- setBeanName -- BeanNameAware -- " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("第四步 -- BeanInit -- setBeanClassLoader -- BeanClassLoaderAware -- " + classLoader);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @InitBinder
    public void start(){
        System.out.println("BeanInit -- start -- 自定义方法");
    }
}
